package wangwenjun.phase3.executor.completablefuture.demo01;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.concurrent.CompletableFuture;

/**
 * @author ChangLiang
 * @date 2020/6/23
 */
@Slf4j
public class AppV3Test {

    private UserObject userObject;

    private DeviceObject deviceObject;

    @BeforeEach
    public void setUp() {
        userObject = new UserObject();
        userObject.setName("cl");
        userObject.setMobile("13233333333");

        deviceObject = new DeviceObject();
        deviceObject.setDeviceNo("xxxxooooo");
        deviceObject.setMobile("13233333333");
    }

    @Test
    @DisplayName("test")
    public void test() throws InterruptedException {
        log.warn("start");
        /**
         * 异步执行 直接返回
         * 由于使用了runAfterBoth 其是依次执行的 只不过没有使用main thread来执行
         */
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> DbService.insertReportTable1(userObject))
                .thenRunAsync(() -> DbService.insertReportTable2(deviceObject))
                .whenComplete((v, t) -> log.info("finish"));
        log.warn("finish immediately");
        Thread.currentThread().join();
    }

    @Test
    @DisplayName("test")
    public void test2(){
        /**
         * 同步执行
         *
         * 全部使用main线程同步执行
         * 由于使用了runAfterBoth 其是依次执行的
         * runAfterBoth 其最后的action并不关心返回结果
         */
        log.warn("started");
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> userObject)
                .thenAccept(obj -> DbService.insertReportTable1(obj))
                .runAfterBoth(
                        CompletableFuture.supplyAsync(() -> deviceObject)
                                .thenAccept(obj -> DbService.insertReportTable2(deviceObject)), () -> log.info("finished"));
        log.warn("finish immediately");
    }

    @Test
    @DisplayName("test")
    public void test3(){
        /**
         * 同步执行
         *
         * 使用了thenAcceptAsync 所以insertReportTable1使用了ForkJoinPool
         * 由于使用了runAfterBoth 其是依次执行的
         * 而insertReportTable2由于没有使用ForkJoinPool 所以扔使用main
         */
        log.warn("started");
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> userObject)
                .thenAcceptAsync(obj -> DbService.insertReportTable1(obj))
                .runAfterBoth(
                        CompletableFuture.supplyAsync(() -> deviceObject)
                                .thenAccept(obj -> DbService.insertReportTable2(deviceObject)), () -> log.info("finished"));
        log.warn("finish immediately");
    }

    @Test
    @DisplayName("test")
    public void test4() throws InterruptedException {
        /**
         * 同步执行
         *
         * 使用了thenAcceptAsync 所以insertReportTable1使用了ForkJoinPool
         * 由于使用了runAfterBothAsync 其是同时执行的
         * 而insertReportTable2由于没有使用ForkJoinPool 所以扔使用main
         *
         */
        log.warn("started");
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> userObject)
                .thenAcceptAsync(obj -> DbService.insertReportTable1(obj))
                .runAfterBothAsync(
                        CompletableFuture.supplyAsync(() -> deviceObject)
                                .thenAccept(obj -> DbService.insertReportTable2(deviceObject)), () -> log.info("finished"));
        log.warn("finish immediately");
    }

    @Test
    @DisplayName("test")
    public void test5() throws InterruptedException {
        /**
         * 异步执行
         *
         * 使用了thenAcceptAsync 所以insertReportTable1使用了ForkJoinPool
         * 由于使用了thenXXX 仍旧是依次执行的
         * 而insertReportTable2 也使用ForkJoinPool
         * 完全异步执行了
         *
         * 不关心返回值的情况下可以使用
         *
         */
        log.warn("started");
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> userObject)
                .thenAcceptAsync(obj -> DbService.insertReportTable1(obj))
                .runAfterBothAsync(
                        CompletableFuture.supplyAsync(() -> deviceObject)
                                .thenAcceptAsync(obj -> DbService.insertReportTable2(deviceObject)), () -> log.info("finished"));
        log.warn("finish immediately");
    }
}
